package cn.zwx.zookeeper.config.example.support;

import cn.zwx.zookeeper.config.example.annotations.ZkRefreshScope;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author zhangwenxue
 */
@Component
public class ConfigurationPropertiesBeans  implements BeanPostProcessor {

    /**
     * 解析出来 RefreshScope下的@Value 保存下来为做动态刷新准备
     */
    private Map<String, List<FieldPair>> fieldMapper=new HashMap<>();

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        Class clz=bean.getClass();
        //如果某个bean声明了ZkRefreshScope注解，说明需要进行动态更新
        if(clz.isAnnotationPresent(ZkRefreshScope.class)){
            for(Field field:clz.getDeclaredFields()){
                //得到带有Value注解的filed @Value("${name}")
                Value value=field.getAnnotation(Value.class);
                if(value==null){
                    continue;
                }
                List<String> keyList=getPropertyKey(value.value(),0);
                for (String key:keyList){
                    // 进行一个保存
                    fieldMapper.computeIfAbsent(key,(k)->new ArrayList())
                            .add(new FieldPair(bean,field,value.value()));
                }
            }
        }
        return bean;
    }

    /**
     * 提取属性值 :之前是 key 之后是默认值
     */
    private List<String> getPropertyKey(String value, int begin) {
        int start=value.indexOf("${",begin)+2;
        if(start<2){
            return new ArrayList<>();
        }
        int middle=value.indexOf(":",start);
        int end=value.indexOf("}",start);
        String key;
        if(middle>0&&middle<end){
            key=value.substring(start,middle);
        }else{
            key=value.substring(start,end);
        }
        List<String> keys=getPropertyKey(value,end);
        keys.add(key);
        return keys;
    }

    public Map<String, List<FieldPair>> getFieldMapper() {
        return fieldMapper;
    }
}
